from random import randint

from django.http import HttpResponse
from django.shortcuts import render
from rest_framework.views import APIView
# Create your views here.
from rest_framework import status, mixins
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
from rest_framework_jwt.views import ObtainJSONWebToken

from carts.utils import merge_cart_cookie_to_redis
from libs.captcha import captcha
from users.models import User
from users.utils import generic_verify_url, check_verify_email_token
from utils.password import send_token, generate_safe_user_token, check_save_token_get_user
from utils.users import get_user_by_account
from rest_framework.permissions import IsAuthenticated


class UserCenterPassAPIView(APIView):

    permission_class = [IsAuthenticated]

    def put(self, request, use_id):

        data = request.data
        old_password = data.get('old_password')
        user = User.objects.filter(id=use_id)[0]
        if not user.check_password(old_password):
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            password = data.get('password')
            password2 = data.get('password2')
            if password != password2:
                return Response(status=status.HTTP_404_NOT_FOUND)

            user.set_password(password)
            user.save()

            return Response({'msg': 'ok'})


class FindPasswordView(APIView):

    def get(self, request, image_code_id):

        text, image = captcha.generate_captcha()

        redis_conn = get_redis_connection("code")

        redis_conn.setex("img_%s" % image_code_id, 60, text)
        print(text)
        return HttpResponse(image, content_type="Image/jpg")


class VerifyAccountExist(APIView):

    def get(self, request, account):

        image_code_id = request.query_params
        serializer = RegisterSmsCodeSerializer(data=image_code_id)
        serializer.is_valid(raise_exception=True)

        try:
            user = get_user_by_account(account)
        except User.DoesNotExist:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        if not user:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        _, token = send_token(user)

        access_token = generate_safe_user_token(token)

        data = {
            "mobile": user.mobile,
            "access_token": access_token
        }

        return Response(data)


class GetSmsCode(APIView):

    def get(self, request):

        token = request.query_params.get("access_token")

        user_id = check_save_token_get_user(token)
        try:
            user = User.objects.get(id=user_id)
        except User.DoesNOtExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

        mobile = user.mobile

        # TODO
        # '%06d' % randint(0, 999999)
        sms_code = '%06d' % randint(0, 999999)
        print(sms_code)

        redis_conn = get_redis_connection("code")
        redis_conn.setex("sms_%s" % mobile, 60, sms_code)
        from celery_tasks.sms.tasks import send_sms_code
        send_sms_code.delay(mobile, sms_code)
        return Response({"message": "OK"})


class VerifySmsCode(APIView):
    # GET /accounts/aaaaa/password/token/?sms_code=084054
    # user_id, access_token
    def get(self, request, account):

        user = User.objects.get(username=account)

        sms_code = request.query_params.get("sms_code")
        mobile = user.mobile

        if not sms_code:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        redis_conn = get_redis_connection("code")
        real_sms_code = redis_conn.get("sms_%s" % mobile)

        if not real_sms_code:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        if real_sms_code.decode() != sms_code:
            return Response(status=status.HTTP_403_FORBIDDEN)

        _, token = send_token(user)
        access_token = generate_safe_user_token(token)

        data = {
            "access_token": access_token,
            "user_id": user.id
        }
        return Response(data)


class NewPassword(APIView):
    # "POST /users/10/password/
    # return
    def post(self, request, user_id):
        password = request.data.get("password")
        password2 = request.data.get("password2")

        if not password2 and password:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        if password != password2:
            return Response(status=status.HTTP_400_BAD_REQUEST)
        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:

            return Response(status=status.HTTP_400_BAD_REQUEST)

        user.set_password(password)
        user.save()

        return Response({"message": "OK"})


class UserAuthorizationView(ObtainJSONWebToken):

    def post(self, request):
        # 调用jwt扩展的方法，对用户登录的数据进行验证
        response = super().post(request)

        # 如果用户登录成功，进行购物车数据合并
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            # 表示用户登录成功
            user = serializer.validated_data.get("user")
            # 合并购物车
            #merge_cart_cookie_to_redis(request, user, response)
            response = merge_cart_cookie_to_redis(request, user, response)

        return response


"""
需求:
    把需求(用户做了什么,前端需要传递什么,我们后端要干什么)写下来
    用户在输入框中输入了用户名,前端需要将用户名提交给后端,后端需要验证用户名是否重复
    
后端的思路:
    需求:
        判断用户名是否重复 可以返回给前端一个标记(true/false)
                        也可以返回一个 count  count:0 没有注册过
                                           count:1  有注册过
    1.确定前端需要传递什么数据给后端
        把一些简要的步骤写下来
        1.查询数据库
        2.返回一个count
    2.确定请求方式 和 路由
        get   users/usernames/itcast/
              users/usernames/(?P<username>\w{5,20})/
              users/usernames/(?P<username>\w{5,20})/count/
        post
        put
        delete
    3.确定使用哪个视图
        APIView                       :DRF的基类
        GeneriAPIView                 :对列表视图和详情视图做了通用支持,一般和Mixin扩展使用
        ListAPIView,RetrieveAPIView   :连get方法都不用写,自动调用系统的mixin实现对数据的操作

    4.按照我们的需求分析,实现步骤开发就可以
"""

from rest_framework.views import APIView, APIView, APIView

from rest_framework.generics import GenericAPIView, UpdateAPIView


class RegisterUsernameCountAPIView(GenericAPIView):

    def get(self,request,username):
        # 通过模型查询,获取用户名个数
        count = User.objects.filter(username=username).count()
        # 组织数据
        context = {
            'count': count,
            'username': username
        }
        return Response(context)


class RegisterPhoneCountAPIView(APIView):

    def get(self, request,mobile):
        count = User.objects.filter(mobile=mobile).count()
        context = {
            'count': count,
            'phone': mobile
        }
        return Response(context)


from rest_framework.generics import CreateAPIView
from .serializers import *


class RegisterCreateView(CreateAPIView):
    serializer_class = RegisterCreateSerializer

"""
需求:必须是登录用户才可以显示个人中新,而且是 需要让前端将用户信息传递过来
认证方式采用的jwt
我们让前端把token传递过来
后端:
    1.接受用户信息
    2.根据用户信息进行查询(user)
    3.将user对象转换为字典,返回
    确定请求方式
    GET /users/infos/
    RetrieveAPIView
"""
# from rest_framework.mixins import RetrieveModelMixin
from rest_framework.permissions import IsAuthenticated, IsAuthenticated, IsAuthenticated, IsAuthenticated, \
    IsAuthenticated

# class UserCenterInfoAPIView(APIView):
#     permission_classes = [IsAuthenticated]
#     # 这个接口,只能是登录用户才能访问
#
#     def get(self,request):
#         # 1.接受用户信息
#         # .在这里结合用户权限,我们就获取到了用户信息
#         user = request.user
#         # 2.将对象转换为字典
#         serializer = UserCentetInfoSerializer(user)
#         # 3.返回数据
#         return Response(serializer.data)
from rest_framework.generics import RetrieveAPIView


class UserCenterInfoAPIView(RetrieveAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = UserCentetInfoSerializer
    # 重新 mixin扩展中的 get_object方法

    def get_object(self):

        return self.request.user

"""
邮箱的逻辑

当用户输入邮箱之后,点击保存,这个时候,前端需要将邮箱发送给后端

后端:
    1.接受邮箱信息
    2.保存邮箱信息到数据库中
    3.发送一封激活邮件
    4.用户点击激活邮件的时候,我们需要修改邮件的标记为,由未激活变为已激活
    
"""


"""
更新邮箱的逻辑是:
# 1.让前端将邮箱以及token传递给后端
# 2.后端接受数据
# 3.更新制定用户的信息
# 4.返回响应
"""

class EmailUpdateView(APIView):
    permission_classes = [IsAuthenticated]

    def put(self,request):
        # 获取ip地址
        if request.META.get('HTTP_X_FORWARDED_FOR',None) is not None:
            ip = request.META['HTTP_X_FORWARDED_FOR']
        else:
            ip = request.META['REMOTE_ADDR']
        username = request.user.username
            # 1.让前端将邮箱以及token传递给后端
        # 2.后端接受数据
        data = request.data
        # 3.更新制定用户的信息
        user = request.user

        serializer = EmailSerializer(instance=user,data=data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 发送邮件
        from django.core.mail import send_mail
        subject = '美多商城激活邮件'
        from_email = '美多商城<xc6@tom.com>'
        email = request.data.get('email')
        recipient_list=[email]
        verify_url = generic_verify_url(request.user.id,email)
        from celery_tasks.email.tasks import send_verify_mail
        send_verify_mail.delay(username,email, verify_url, ip)
        # 4.返回响应
        return Response(serializer.data)

class VerificationEmailView(APIView):
    """
        验证激活邮箱
        GET /users/emails/verification/?token=xxxx

        思路:
        获取token,并判断
        获取 token中的id
        查询用户,并判断是否存在
        修改状态
        返回响应
    """
    def get(self,request):
        token = request.query_params.get('token')
        if not token:
            return Response({'message':'链接无效'},status=status.HTTP_400_BAD_REQUEST)
        user = check_verify_email_token(token)
        if user is None:
            return Response({'message': '链接无效'}, status=status.HTTP_400_BAD_REQUEST)
        else:
            user.email_active = True
            user.save()
            return Response({'message': 'ok'})


class AddressViewSet(mixins.ListModelMixin,mixins.CreateModelMixin,mixins.UpdateModelMixin,GenericViewSet):
    """
    用户地址新增与修改
    list GET: /users/addresses/
    create POST: /users/addresses/
    destroy DELETE: /users/addresses/
    action PUT: /users/addresses/pk/status/
    action PUT: /users/addresses/pk/title/
    """
    # 制定序列化器
    serializer_class = AddressSerializer

    # 添加用户权限
    permission_classes = [IsAuthenticated]

    # 由于用户的地址有存在删除的状态,所以我们需要对数据进行筛选
    def get_queryset(self):
        return self.request.user.addresses.filter(is_deleted=False)

    def create(self, request, *args, **kwargs):
        """
        保存用户地址数据
        """
        count = request.user.addresses.count()
        if count >= 20:
            return Response({'message':'保存地址数量已经达到上限'},status=status.HTTP_400_BAD_REQUEST)

        return super().create(request,*args,**kwargs)

    def list(self, request, *args, **kwargs):
        """
        获取用户地址列表
        """
        # 获取所有地址
        queryset = self.get_queryset()
        # 创建序列化器
        serializer = self.get_serializer(queryset, many=True)
        user = self.request.user
        # 响应
        return Response({
            'user_id': user.id,
            'default_address_id': user.default_address_id,
            'limit': 20,
            'addresses': serializer.data,
        })

    def destroy(self, request, *args, **kwargs):
        """
        处理删除
        """
        address = self.get_object()

        # 进行逻辑删除
        address.is_deleted = True
        address.save()

        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(methods=['put'], detail=True)
    def title(self, request, pk=None, address_id=None):
        """
        修改标题`11``123456+SAC VV
        """
        address = self.get_object()
        serializer = AddressTitleSerializer(instance=address, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)

    @action(methods=['put'], detail=True)
    def status(self, request, pk=None, address_id=None):
        """
        设置默认地址
        """
        address = self.get_object()
        request.user.default_address = address
        request.user.save()
        return Response({'message': 'OK'}, status=status.HTTP_200_OK)


"""
1.当登录用户访问商品详情的时候,需要让前端发送一个请求,将商品id和用户信息发送给后端
    用户信息让前端以token的形式传递过来
    
    sku_id,user_id
    1     :[2,3,4,5,6]
    
    Redis
    
    String字符串:       key:value
    
    List 列表:         key:[value1,value2]
    
    Hash 哈系:         key:field:value
                        field1:value1
                        field2:value2
    Set 集合(不重复):   key:[value2,value1,value3]
    
    ZSet 有序集合:      key:[value1,value2,value3]   
后端:
    接口只能是登录用户访问
    大体步骤:
        接受数据
        验证数据
        把数据保存起来
        返回响应
    请求方式和路由
        POST /users/browerhistories/
    
2.当登录用户访问个人中心的时候,需要获取当前用户的浏览记录
"""


class UserBrowsingHistoryView(CreateAPIView):
    serializer_class = UserHistroySerializer
    permission_classes = [IsAuthenticated]

    def get(self,request):
        # 获取用户信息
        user_id = request.user.id
        # 连接redis
        redis_conn = get_redis_connection('history')
        # 获取数据
        history_sku_ids = redis_conn.lrange('history_%s' % user_id, 0, 5)
        # 原有的顺序就不存在了
        # skus = SKU.objects.filter(pk__in=history_sku_ids)
        skus = []
        for sku_id in history_sku_ids:
            sku = SKU.objects.get(pk=sku_id)
            skus.append(sku)
        serializers = SKUSerializer(skus,many=True)
        return Response(serializers.data)

